package com.demo.common;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.WritableRaster;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;

/**
 * 图片处理工具类
 * 对图片进行缩放和剪切
 * @author
 *
 */
public final class ImageUtils {
	
	public static final String PNG = "png";
	
	public static final String JPG = "jpg";
	/**
	 * 构造函数
	 */
	private ImageUtils() { }
	
	 /**
     * 生成缩略图的宽度
     */
	private static final int IMG_SMALL_WIDTH = 100;
    
    /**
     * 生成缩略图的高度
     */
	private static final int IMG_SMALL_HEIGHT = 122;
	
	
	/**
	 * 生成缩略图
	 * @param file 图片文件
	 * @return 小图
	 */
	public static byte[] toThumbnail(File file) {
		return ImageUtils.toThumbnail(file, IMG_SMALL_WIDTH, IMG_SMALL_HEIGHT, false);
	}
	
	/**
	 *  @param  file 源文件
	 *  @param 	targetWidth 生成图片的宽度
	 *  @param 	targetHeight 生成图片的高度
	 *  @return 返回一个byte数组
	 */
	public static byte[] toThumbnail(File file, int targetWidth, int targetHeight, boolean keepResize) {
		BufferedImage src = null;
		try {
			src = ImageIO.read(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//实现等比缩放
		BufferedImage tagImage = null;
		
		if (keepResize) {
			//保持原图长宽比
			tagImage = ImageUtils.imageZoom(src, targetWidth, targetHeight);
		} else {
			// 截图
			BufferedImage cutImage = ImageUtils.cutSrcImage(src, targetWidth, targetHeight);
			// 缩放
			tagImage= ImageUtils.imageZoom(cutImage, targetWidth, targetHeight);
		}
		return ImageUtils.bufferedImageToByte(tagImage, JPG);
	}
	
	/**
	 *  @param  file 源文件
	 *  @param 	targetWidth 生成图片的宽度
	 *  @param 	targetHeight 生成图片的高度
	 *  @param  keepResize 是否保持原图比例
	 *  @param  output OutPutStream
	 *  @return 返回一个byte数组
	 *  @throws IOException IO错误
	 */
	public static void toThumbnail(File file, String format, int targetWidth, int targetHeight, boolean keepResize, OutputStream output) throws IOException {
		BufferedImage src = null;
		try {
			src = ImageIO.read(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//实现等比缩放
		BufferedImage tagImage = null;
		
		if (keepResize) {
			//保持原图长宽比
			tagImage = ImageUtils.imageZoom(src, targetWidth, targetHeight);
		} else {
			// 截图
			BufferedImage cutImage = ImageUtils.cutSrcImage(src, targetWidth, targetHeight);
			// 缩放
			tagImage= ImageUtils.imageZoom(cutImage, targetWidth, targetHeight);
		}
		ImageIO.write(tagImage, format, output);
	}
	
	/**
	 * 取得PNG缩略图
	 *  @param  file 源文件
	 *  @param 	targetWidth 生成图片的宽度
	 *  @param 	targetHeight 生成图片的高度
	 * @param keepResize 是否保持原图比例
	 *  @return 返回一个byte数组
	 */
	public static byte[] toPNGThrumbnail(File file, int targetWidth, int targetHeight, boolean keepResize) {
		
		BufferedImage src = null;
		try {
			src = ImageIO.read(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//实现等比缩放
		BufferedImage tagImage = null;
		
		if (keepResize) {
			//保持原图长宽比
			tagImage = ImageUtils.imageZoom(src, targetWidth, targetHeight);
		} else {
			// 截图
			BufferedImage cutImage = ImageUtils.cutSrcImage(src, targetWidth, targetHeight);
			// 缩放
			tagImage= ImageUtils.imageZoom(cutImage, targetWidth, targetHeight);
		}
		
		PngEncoderB pngImage = new PngEncoderB(tagImage);
		
		return pngImage.pngEncode();
	}
	
	/**
	 * 先对根据目标尺寸对图像进行截取，符合缩放比例
	 * @return cutImage
	 * @param width 宽度
	 * @param height 高度
	 * @return BufferedImage 原图
	 */
	private static BufferedImage cutSrcImage(BufferedImage srcImage, int width, int height) {
		//原图的高和宽
		BufferedImage cutImage = null;
		int srcWidth = srcImage.getWidth();
		int srcHeight = srcImage.getHeight();
		double sx = (double) width / srcWidth;
		double sy = (double) height / srcHeight;

		//截取后的宽度和高度
		int cutWidth = 0;
		int cutHeight = 0;
		// 确定根据比例截图的尺寸
		if (sx < sy) {
			cutWidth = (int) (srcHeight * width / height);
			cutHeight = srcHeight;
			// 图像的宽度进行截取
			// 计算矩形坐标
			int x = srcWidth / 2 - cutWidth / 2;
			int y = 0;
			try {
				cutImage = saveSubImage(srcImage, new Rectangle(x, y, cutWidth, cutHeight));
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			cutHeight = (int) (srcWidth * height / width);
			cutWidth = srcWidth;
			//图像的高度进行截取
			//计算矩形坐标
			int x = 0;
			int y = srcHeight / 2 - cutHeight / 2;
			try {
				cutImage = saveSubImage(srcImage, new Rectangle(x, y, cutWidth, cutHeight));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return cutImage;
	}
	
	 /**
	  * 保存截取后的图片
	  * @param image 图片
	  * @param subImageBounds 坐标
	  * @throws IOException 异常
	  * @return subImge 截取后的图片对象
	  */
	private static BufferedImage saveSubImage(BufferedImage image, Rectangle subImageBounds) throws IOException {
		if (subImageBounds.x < 0 || subImageBounds.y < 0
				|| subImageBounds.width - subImageBounds.x > image.getWidth()
				|| subImageBounds.height - subImageBounds.y > image.getHeight()) {
			System.out.println("Bad   subimage   bounds");
			return null;
		}
		BufferedImage subImage = image.getSubimage(subImageBounds.x, subImageBounds.y, 
				subImageBounds.width, subImageBounds.height);
		return subImage;
	}
	
	/**
	 * 直接缩放成符合要求的图片
	 * 注意:如果原始图片与输入图片之间的宽高比不同,
	 * 则以变化最大的那一个作为基准
	 * 比如,原图w:h = 100:120,缩略图w:h = 50:50
	 * 那么,缩略图的h为50(与原图h比>w之比),作为基准,进行缩放
	 * 输入的缩略图为:125/3 ≈ 41.7
	 * @return tag
	 * @param cutImage 剪切过的图片
	 * @param width    目标图片宽度
	 * @param height	目标图片高度
	 */
	public static BufferedImage imageZoom(BufferedImage cutImage, int width, int height) {
		BufferedImage tag = null;
		int type = cutImage.getType();
		
		int srcWidth = cutImage.getWidth();
		int srcHeight = cutImage.getHeight();
		
		double sx = (double) width / srcWidth;
		double sy = (double) height / srcHeight;
		double sz1 = (double) width / height;
		double sz2 = (double) srcWidth / srcHeight;
		
		if (sz1 > sz2) {
			//原始图高度过大
			//新宽度不能为给定的值,需要根据高度的缩小比例进行计算
			Double tmp = (double) sy * srcWidth;
			width = tmp.intValue();
		} else if (sz1 < sz2) {
			//原始图片宽度过大
			//新高度不能为给定值,根据宽度的缩小比例,进行高度的调整
			Double tmp = (double) sx * srcHeight; 
			height = tmp.intValue();
		}
		
		// 如果返回位置类型，则手动绘图
		if (type == BufferedImage.TYPE_CUSTOM) {
			ColorModel cm = cutImage.getColorModel();
			WritableRaster raster = cm.createCompatibleWritableRaster(width,
					height);
			boolean alphaPremultiplied = cm.isAlphaPremultiplied();
			tag = new BufferedImage(cm, raster, alphaPremultiplied, null);
		} else {
			tag = new BufferedImage(width, height, type);
			tag.getGraphics().drawImage(cutImage.getScaledInstance(width, height, 
					Image.SCALE_SMOOTH), 0, 0,  null);
		}
		return tag;
	}
	
	/**
	 * BufferedImage对象转化成字节数组
	 * @param srcImage  bufferedImage对象
	 * @return data 比特数组
	 */
	private static byte[] bufferedImageToByte(BufferedImage srcImage, String format) {
		ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
		byte[] data = null;
		try {
			//把图像写到流中去
			ImageIO.write(srcImage, format, imageStream);
			
			//bufferImage转化成比特数组
			data = imageStream.toByteArray();
			imageStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		 return data;
	}
	
	/**
	 * 读取一张图片
	 * @param input 输入流
	 * @return BufferedImage对象
	 */
	public static final BufferedImage buildImage(InputStream input) {
		
		BufferedImage image = null;
		try {
			image = ImageIO.read(input);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return image;
	}
	
	/**
	 * 已矩形切分图片
	 * 根据图片的坐标xy和切分的size(width:height)进行切分。
	 * @return BufferedImage
	 */
	public static final BufferedImage cropImage(InputStream input, int x, int y, int w, int h) {
		CropImageFilter imageFilter = new CropImageFilter(x, y, w, h);
		BufferedImage image = buildImage(input);
		//byte[] bits = ImageUtils.bufferedImageToByte(image, JPG);
		Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), imageFilter));
		BufferedImage tag = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		Graphics graph = tag.getGraphics();
		graph.drawImage(img, 0, 0, null);
		graph.dispose();
		return tag;
	}
}
